﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using thinger.DataConvertLib;

namespace SerialPortDemo_03
{
    public partial class MainForm : Form
    {
        private SerialPort serialPort = new SerialPort();

        // 接收数据缓存
        private MemoryStream memoryBuffer = new MemoryStream();

        // 串口打开标识
        private bool open = false;

        // 操作标识
        private int action = -1; // 0 读取; 1 请求解析读取

        // 按钮控制列表
        private List<Button> buttonList = new List<Button>();

        public MainForm()
        {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            // 获取当前可识别的串口
            string[] port = System.IO.Ports.SerialPort.GetPortNames();

            // 初始化界面
            comboBoxPortName.Items.AddRange(port);
            // 如果有数据显示第0个
            comboBoxPortName.SelectedIndex = comboBoxPortName.Items.Count > 0 ? 0 : -1;

            comboBoxBaudRate.Items.Add(1200);
            comboBoxBaudRate.Items.Add(4800);
            comboBoxBaudRate.Items.Add(9600);
            comboBoxBaudRate.Items.Add(14400);
            comboBoxBaudRate.Items.Add(19200);
            comboBoxBaudRate.Items.Add(38400);

            comboBoxBaudRate.SelectedItem = 9600;

            // 按钮加入控制列表
            buttonList.Add(buttonRead);
            buttonList.Add(buttonRead1);
        }

        private void buttonOpen_Click(object sender, EventArgs e)
        {
            try
            {
                if (!open)
                {
                    serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPortDataReceived);
                    serialPort.PortName = comboBoxPortName.Text;
                    serialPort.BaudRate = int.Parse(comboBoxBaudRate.Text);
                    serialPort.DataBits = 8;
                    serialPort.StopBits = StopBits.One;
                    serialPort.Parity = Parity.None;
                    serialPort.Open();

                    buttonOpen.Text = "关闭串口";
                    open = true;
                }
                else
                {
                    serialPort.Close();

                    buttonOpen.Text = "打开串口";
                    open = false;
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                serialPort = (SerialPort)sender;
                byte[] bytebuffer = new byte[serialPort.BytesToRead];
                serialPort.Read(bytebuffer, 0, bytebuffer.Length);
                // 将接收到的数据写入缓存
                memoryBuffer.Write(bytebuffer);

                Debug.WriteLine("-------");
                Debug.WriteLine("mem length:" + memoryBuffer.Length);

                // 判断缓存长度 至少包括数据长度
                if (memoryBuffer.Length <= 2)
                {
                    return;         
                }

                // 整包数据长度
                byte length = (byte)(ByteLib.GetByteFromByteArray(memoryBuffer.ToArray(), 2) + 5);

                Debug.WriteLine("length:" + length);

                // 判断缓存长度 
                if (memoryBuffer.Length < length)
                {
                    return;                 
                }

                byte[] temp = new byte[length - 2 ];
                byte[] tempCRC = new byte[2];

                Array.Copy(memoryBuffer.ToArray(), temp, temp.Length );
                Array.Copy(memoryBuffer.ToArray(), temp.Length , tempCRC, 0, 2);

                byte[] needCheckTemp = CRC.crc16(temp);

                Debug.WriteLine(StringLib.GetHexStringFromByteArray(temp) + " / " + StringLib.GetHexStringFromByteArray(tempCRC) + " ");
                Debug.WriteLine(StringLib.GetHexStringFromByteArray(needCheckTemp));
                Debug.WriteLine(!(tempCRC[0] == needCheckTemp[length - 2] && tempCRC[1] == needCheckTemp[length - 1]));
                Debug.WriteLine(tempCRC[0] + " " + needCheckTemp[length - 2] + " " + tempCRC[1] + " " + needCheckTemp[length - 1]);

                // 数据长度满足条件，判断校验位
                if (!(tempCRC[0] == needCheckTemp[length - 2] && tempCRC[1] == needCheckTemp[length - 1]))
                {
                    // 缓存清空
                    memoryBuffer = new MemoryStream();
                    // 操作标识重置
                    action = -1;

                    // 按钮恢复
                    Invoke(new Action(() => buttonList.ForEach(button => button.Enabled = true)));

                    return;
                }

                // 判断操作
                switch (action)
                {
                    case 0:
                        // 接收事件与界面并不是同一个线程；所以需要用Invoke()方法同步更新界面
                        Invoke(new Action(() => textBoxLog.AppendText("收到响应：" + StringLib.GetHexStringFromByteArray(temp) + "\r\n")));
                        MessageBox.Show("读取完成");
                        break;

                    case 1:
                        // 接收事件与界面并不是同一个线程；所以需要用Invoke()方法同步更新界面
                        Invoke(new Action(() => {

                            // 响应的数据
                            // 01 03 06 00 00 00 02 00 00 80 B5
                            // 0x01 -- 从机地址；  0x03 -- 功能码； 0x06 -- 数据长度
                            // 0x00 0x00 -- 第一个寄存器的值
                            // 0x00 0x02 -- 第二个寄存器的值
                            // 0x00 0x00 -- 第三个寄存器的值
                            // 0x80 0xB5 -- 校验位

                            byte[] data = new byte[6];
                            Array.Copy(temp, 3, data, 0, 6);

                            // 将数据填到对应输入框中
                            textBoxAddress1.Text = ShortLib.GetShortFromByteArray(data).ToString();
                            textBoxAddress2.Text = ShortLib.GetShortFromByteArray(data, 2).ToString();
                            textBoxAddress3.Text = ShortLib.GetShortFromByteArray(data, 4).ToString();
                            textBoxLog.AppendText("收到响应：" + StringLib.GetHexStringFromByteArray(memoryBuffer.ToArray()) + "\r\n");

                            MessageBox.Show("读取完成");
                        }));
                        break;
                }

                // 缓存清空
                memoryBuffer = new MemoryStream();
                // 操作标识重置
                action = -1;

                // 按钮恢复
                Invoke(new Action(()=> buttonList.ForEach(button => button.Enabled = true)));

            }
            catch (Exception)
            {
                throw;
            }
        }

        private void buttonRead_Click(object sender, EventArgs e)
        {
            try
            {
                // 按钮失效
                buttonList.ForEach(button => button.Enabled = false);
                // 定义操作标识
                action = 0;
             
                // 0x01 -- 从机地址；  0x03 -- 功能码； 0x00 -- 高位起始地址
                // 0x00 -- 低位起始地址； 0x00 -- 高位读取寄存器个数
                // 0x09 -- 低位读取寄存器个数
                // 0x85 0xCC -- 校验位
                byte[] request = new byte[] { 0x01, 0x03, 0x00, 0x00, 0x00, 0x64, 0x44, 0x21 };

                //byte[] request = new byte[] { 0x01, 0x03, 0x00, 0x00, 0x00, 0x9, 0x85, 0xCC };

                textBoxLog.AppendText("发送请求：" + StringLib.GetHexStringFromByteArray(request) + "\r\n");
                serialPort.Write(request, 0, request.Length);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void buttonRead1_Click(object sender, EventArgs e)
        {
            try
            {
                // 按钮失效
                buttonList.ForEach(button => button.Enabled = false);
                // 定义操作标识
                action = 1;            

                byte[] request = new byte[] { 0x01, 0x03, 0x00, 0x01, 0x00, 0x03, 0x54, 0x0B };

                                        // 缓存清空
                memoryBuffer = new MemoryStream();

                textBoxLog.AppendText("发送请求：" + StringLib.GetHexStringFromByteArray(request) + "\r\n");
                serialPort.Write(request, 0, request.Length);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}
